<html xmlns="http://www.w3.org/1999/xhtml" id="persistent_connection">
<head>
    <title>The Persistent Connection</title>
</head>

<body>

<h1>The Persistent Connection</h1>
 
<warning>This feature is provisional.  It works in limited capacity
situations and is fine to develop with, but we do not recommend
deployment (with the possible exception of low-capacity, non-mission
critical deployment) with this feature. Please consult Laszlo directly
if you have questions about the robustness of an application that uses
this version of the persistent connnection.
</warning>

<p>This document describes persistent connection concepts, definitions, and
elements. It also demonstrates how to program in LZX using the persistent
connection. It assumes you have a basic knowledge of LZX (in particular,
datasets and datapointers) and a basic understanding of servlet containers and
HTTP cookies/sessions.</p>


<!--=========================================================================-->
<!-- Overview                                                                -->
<!--=========================================================================-->
<h2><a name="overview"/>Overview</h2>

<p>A <dfn>persistent connection</dfn> is a one-way pipe held by an application from
the LPS. Because all transactions are done through an HTTP port, it allows an
application to receive asynchronous messages from the server without the need to
open up a port in the firewall. Maintanance of an application's persistent
connection is done by the <a href="#connection-manager"><dfn>connection
manager</dfn></a>, whose job is to multiplex all incoming data into a connection
dataset. A <a href="#connection-datasource"><dfn>connection datasource</dfn></a> is
used to declare connection datasets. Each connection datasource registers itself
with the connection manager. This allows the connection manager to look through
its list of connection datasources to see if there's a dataset that matches the
destination of an incoming message. It's possible that two separate datasets
receive the same message if different datasources declare datasets with the same
name. Assuming the following:</p>

<pre>
&lt;connectiondatasource name="one"&gt;
  &lt;dataset name="message"&gt;
  &lt;dataset name="alert"&gt;
&lt;/connectiondatasource&gt;

&lt;connectiondatasource name="two"&gt;
  &lt;dataset name="stock"&gt;
  &lt;dataset name="alert"&gt;
&lt;/connectiondatasource&gt;
</pre>


<p>datasets <code>one.alert</code> and <code>two.alert</code> will receive the
same data for messages destined for "alert".</p>


<!--=========================================================================-->
<!-- The connection manager                                                  -->
<!--=========================================================================-->
<h2><a name="connection-manager"/>The connection manager</h2>

<p>The connection manager is an <code>LzConnection</code> object that is
instantiated when <code>&lt;connection&gt;</code> is declared in the
canvas (note: <code>&lt;connection&gt;</code> can't be declared in a
library). Once constructed, the connection manager can be accessed using
<code>canvas.connection</code>.</p>

<example title="Simple connection manager">
  &lt;canvas height="120" debug="true">
      &lt;connection/>
      &lt;script>
          Debug.write('my connection manager: ' + canvas.connection);
      &lt;/script>
  &lt;/canvas>
</example>

<p>To establish a persistent connection to the LPS, use the
<method>LzConnection.connect</method> method.</p>

<example extract="false">
  &lt;canvas>
      &lt;connection authenticator="anonymous"/>
      &lt;script>
        canvas.connection.connect();
      &lt;/script>
  &lt;/canvas>
</example>

<p>An anonymous <dfn>authenticator</dfn> tells the connection that it doesn't
require authentication. An authenticator ensures connection requests to the
server are authorized. By default, the connection validates its request is valid
by calling a back-end authentication server. See <a
href="#authentication">Authentication</a> for more details.</p>

<p>Once a connection is established, it is identified with a <dfn>username</dfn> and
a unique <dfn>connection session id</dfn>. The username gives the connection a
target for other clients to use for sending messages. Multiple connection
sessions may have the same username. You can get these values by calling
<method>LzConnection.getUsername</method> and
<method>LzConnection.getSID</method>.</p>

<h3><a name="connection-attributes"/>attributes</h3>

<p>You can modify the behavior of the persistent connection by
changing attributes in the connection tag. The available attributes
are:</p>

<dl>
<dt><attribute>group</attribute></dt>
<dd>used to name the connection group an application's persistent
connection belongs to</dd>
<dt><attribute>secure</attribute><attribute>secureport</attribute></dt>
<dd>used to establish a secure persistent
connection</dd>
<dt><attribute>heartbeat</attribute>/<attribute>timeout</attribute></dt>
<dd>sets the frequency the LPS checks to see
if an application is still listening to the persistent connection</dd>
<dt><attribute>receiveuserdisconnect</attribute></dt>
<dd>if true, receives notification from LPS whenever a
client closes their persistent connection</dd>
<dt><attribute>authenticator</attribute>/<attribute>authparam</attribute></dt>
<dd>the java authentication class to use
in LPS for connection requests</dd>
</dl>

<h4><a name="group"/>group</h4>

<p>A <dfn>connection group</dfn> is a set of connected applications. Messages sent
to a group can be received by other connections registered to that group. A
connection with an unspecified group name has its webapp path as its group. You
can use the <code>group</code> attribute to register your connection to a
group.</p>

<pre>
&lt;connection group="mygroup"/>
</pre>

<p>Clients not registered the same group are not allowed to send messages to
each other.</p>

<h4><a name="secure"/>secure/secureport</h4>

<p>To establish a secure persistent connection, set the <code>secure</code>
attribute to true. Your server must be configured to allow HTTPS requests. You
can also specify a different port if your SSL listener is not on the standard
443 port.</p>

<pre>
&lt;connection secure="true" secureport="8443"/>
</pre>
<p>
Setting the secure attribute also secures connection functions that make
requests to the LPS, e.g., <method>LzConnection.connect</method>,
<method>LzConnectionDatasource.sendMesage</method>, etc.</p>


<h4><a name="heartbeat"/>heartbeat/timeout</h4>

<p>By default, LPS verifies a connection is alive by sending a <dfn>heartbeat</dfn>
every 5 seconds. The connection is configured to timeout if a message or
heartbeat hasn't been heard from the server in 20 seconds. You can change these
values using the <code>heartbeat</code> and <code>timeout</code> attributes,
whose values are in milliseconds.</p>

<pre>
&lt;connection heartbeat="10000" timeout="30000"/>
</pre>

<h4><a name="receiveuserdisconnect"/>receiveuserdisconnect</h4>

<p>An application can be notified through the persistent connection whenever
another client disconnects. To turn this feature on, just set
<code>receiveuserdisconnect</code> to true.</p>

<pre>
&lt;connection receiveuserdisconnect="true"/>
</pre>

<p>This feature is false by default.</p>

<h4><a name="authenticator"/>authenticator/authparam</h4>

<p>An authenticator is a server-side object that validates connection requests.
By default, the connection uses
<code>org.openlaszlo.auth.HTTPAuthentication</code>. By default, this
authenticator contacts the provided authentication servlet located in
<code>http://.../WEBAPP/AuthenticationServlet</code>, where <code>WEBAPP</code>
is the web application path where you installed Laszlo (typically,
<code>lps-@VERSIONID@</code>).</p>


<p>You can use the <code>authenticator</code> attribute to use a different
authenticator for your connection. This attribute expects a java class
name. When the first connection request is made, the server instantiates an
object based on the java class specified. Subsequent calls uses this java
authentication object to authenticate requests. Parameters can be passed into
the java authenticator using the <code>authparam</code> attribute, which expects
a query-styled string. To skip authentication altogether, you can set
<code>authenticator="anonymous"</code>. All connections are named "user" unless
you set <code>authparam="myusername"</code>.</p>

<p>See <a href="#authentication">Authentication</a> for more details.</p>


<h3><a name="connection-methods"/>methods</h3>

<h4><a name="login"/>login(name, password)</h4>

<p>Login allows you to session your application. The connection manager uses its
authenticator for sessioning. Cookies and response headers returned by an
authentication server will be set in the application. The return value of this
call is returned in <code>connection.loginDset</code> with a root element of
&lt;login> like:</p>

<pre>
&lt;login status="message">
  loginXML
&lt;/login>
</pre>

<p>See <a href="#httpauthentication-login">HTTPAuthentication Login</a> for the
login XML return.</p>

<h4><a name="logout"/>The <method>logout</method> method</h4>

<p>Use the <method>logout</method> method to remove an application's session. The return value of this call
is returned in <code>connection.logoutDset</code> with a root element of
&lt;logout like:</p>

<pre>
&lt;logout status="message">
  logoutXML
&lt;/logout>
</pre>

<p>See <a href="#httpauthentication-logout">HTTPAuthentication Logout</a> for
the logout XML return.</p>

<h5>Example:</h5>

<p>This demonstrates how to session and unsession your application.</p>

<pre title="Connection manager login and logout">
&lt;canvas debug="true" height ="200"  &gt;
  &lt;debug y="60"/>
  &lt;connection/>

  &lt;datapointer xpath="connection:loginDset:/login[1]/authentication[1]/response[1]/status[1]"&gt;
    &lt;method event="ondata">
      var statusMessage = this.xpathQuery('@msg');
      Debug.write('login: ' + statusMessage);
    &lt;/method>
    &lt;method event="onerror"&gt;
      Debug.write('login resulted in error');
    &lt;/method>
    &lt;method event="ontimeout">
      Debug.write('login timed out');
    &lt;/method>
  &lt;/datapointer>

  &lt;datapointer xpath="connection:logoutDset:/logout[1]/authentication[1]/response[1]/status[1]"&gt;
    &lt;method event="ondata">
      var statusMessage = this.xpathQuery('@msg');
      Debug.write('logout: ' + statusMessage);
    &lt;/method>
    &lt;method event="onerror">
      Debug.write('logout resulted in error');
    &lt;/method>
    &lt;method event="ontimeout">
      Debug.write('logout timed out');
    &lt;/method>
  &lt;/datapointer>

  &lt;view>
    &lt;simplelayout axis="x" spacing="5"/>
    &lt;button>login
      &lt;method event="onclick">
        canvas.connection.login('adam', 'adam');
      &lt;/method>
    &lt;/button>
    &lt;button>logout
      &lt;method event="onclick">
        canvas.connection.logout();
      &lt;/method>
    &lt;/button>
  &lt;/view>
&lt;/canvas>
</pre>


<h4><a name="connect"/>The <method>connect</method> method</h4>

<p>To establish a connection, you can use the <method>connect</method> method. The
first time <method>connect</method> is called, the connection manager establishes
the connection. Since only once persistent connection can exist per application,
subsequent calls to <method>connect</method> will close the previous connection and establish a
new one.</p>

<h4><a name="disconnect"/>The <method>disconnect</method> method</h4>

<p>Use <method>disconnect</method> to close the persistent connection. This function calls the
server to immediately inform it to close down the connection, as well as closing
down the client-side connection. If you just want to close down the client-side
connection, use <method>clientDisconnect</method>. The benefit to using <method>disconnect</method> is that
the server is immediately informed of the disconnection instead of having to wait
for the next heartbeat. You can view the return status of <method>disconnect</method> using
connection.disconnectDset dataset.</p>

<h5>Example:</h5>

<p>This demonstrates how to use <method>connect</method>, <method>disconnect</method>, and
<method>clientDisconnect</method>.</p>

<example title="Different ways to disconnect">
&lt;canvas debug="true" height="200">
  &lt;debug y="60"/&gt;
  &lt;connection authenticator="anonymous">
    &lt;method event="onconnect">
      Debug.write('connected');
    &lt;/method>
    &lt;method event="ondisconnect">
      Debug.write('client disconnected');
    &lt;/method>
  &lt;/connection>

  &lt;datapointer xpath="connection:disconnectDset:/*[1]">
    &lt;method event="ondata">
      Debug.write('server disconnected');
    &lt;/method>
    &lt;method event="onerror">
      Debug.write('disconnect call to server resulted in error');
    &lt;/method>
    &lt;method event="ontimeout">
      Debug.write('disconnect call to server timed out');
    &lt;/method>
  &lt;/datapointer>

  &lt;view>
    &lt;simplelayout axis="x" spacing="5"/>
    &lt;button>connect
      &lt;method event="onclick">
        canvas.connection.connect();
      &lt;/method>
    &lt;/button>
    &lt;button>disconnect
      &lt;method event="onclick">
        canvas.connection.disconnect();
      &lt;/method>
    &lt;/button>
    &lt;button>client disconnect
      &lt;method event="onclick">
        canvas.connection.clientDisconnect();
      &lt;/method>
    &lt;/button>
  &lt;/view>
&lt;/canvas>
</example>

<!--=========================================================================-->
<!-- The connection datasource                                               -->
<!--=========================================================================-->
<h2><a name="connection-datasource"/>The connection datasource</h2>

<p>While the connection tag configures the behavior of the persistent connection,
the <dfn>connection datasource</dfn> is where you declare the datasets that handle
incoming data. A connection datasource is a LzConnectionDatasource
object. Unlike the connection tag, connection datasources and datasets can be
declared in libraries.</p>

<pre>
&lt;library>
  &lt;connectiondatasource name="mydatasource">
    &lt;dataset name="message"/>
    &lt;dataset name="alert"/>
  &lt;/connectiondatasource>
&lt;/library>
</pre>

<p>When a connection datasource is declared, it registers itself with the
connection manager. In turn, The connection manager routes messages received
from the connection to a connection datasource's dataset.</p>

<p>Since connection datasets only receive data, they will only raise ondata
events. You can handle events raised by the persistent connection through the
connection manager or a connection datasource.</p>

<h3><a name="connectiondatasource-methods"/>LzConnectionDatasource methods</h3>

<p>Many methods in <classname>LzConnectionDatasource</classname>
return their results in a dataset.</p>

<table summary="LzConnectionDatasource Methods">
<tr><th>Methods</th>    <th>Result dataset</th></tr>
<tr><td><code>sendMessage(toList, mesg, dest)</code></td>  <td><code>sendMessageDset</code></td></tr>
<tr><td><code>sendXML(toList, xml, dest)</code></td>       <td><code>sendXMLDset</code></td></tr>
<tr><td><code>sendUserXML(userList, xml, dest)</code></td> <td><code>sendXMLDset</code></td></tr>
<tr><td><code>sendAgentXML(agentList, xml)</code></td>     <td><code>sendXMLDset</code></td></tr>
<tr><td><code>getList(userList)</code></td>                <td><code>getListDset</code></td></tr>
</table>

<p>You can listen for a response status by declaring a datapointer to the
corresponding dataset. An example is shown below.</p>
 
<example title="Sending message over connection">
&lt;canvas debug="true" height="200">
  &lt;debug y="60"/&gt;
  &lt;connection authenticator="anonymous"/>


  &lt;script>
      connection.connect();
  &lt;/script>

  &lt;connectiondatasource name="myconnection">
      &lt;dataset name="messages"/>
  &lt;/connectiondatasource>

  &lt;datapointer xpath="myconnection:messages:/*[1]">
    &lt;method event="ondata">
      var from = this.xpathQuery('/from[0]/@name');
      var mesg = this.xpathQuery('/text()');
      Debug.write('got data from ' + from +  ', mesg is ['+ mesg + ']!');
    &lt;/method>
  &lt;/datapointer>
  
  &lt;datapointer xpath="myconnection:sendMessageDset:/*[1]">
    &lt;method event="ondata">
      Debug.write("*** got result back ***");
    &lt;/method>
  &lt;/datapointer>
  
  &lt;button>send message
    &lt;method event="onclick">
      myconnection.sendMessage('*', 'a message', 'messages');
    &lt;/method>
  &lt;/button>
&lt;/canvas>
</example>

<h4><a name="sendmessage"/>sendMessage() / sendXML()</h4>

<p>There are two ways to send data to other clients: <method>sendMessage</method> and
<method>sendXML</method>. Each send function takes three parameters:</p>

    <ul>
    <li>comma-separated list of destination clients</li>
    <li>message</li>
    <li>destination dataset where the message should be pushed into</li>
    </ul>

<p>The <method>sendMessage</method> method sends a message string. The message is
received by other clients like:</p>

<pre>
&lt;root dset="aDataset">
   &lt;from name="sender"/>
   message string
&lt;/root>
</pre>

<p>The <code>sendXML()</code> call sends arbitray XML data. The sent data looks
like:</p>

<pre>
&lt;root dset="aDataset">
  &lt;XML>
&lt;/root>
</pre>

<p>The results of the call are returned in the connection datasource's
<code>sendMessageDset</code> and <code>sendXMLDset</code>, respectively. Both
<method>sendMessage()</method> and <method>sendXML()</method> send data to <glossterm>users</glossterm> and
<glossterm>agents</glossterm>. You can narrow that domain by using <method>sendUserXML</method> and
<method>sendAgentXML</method>. Users are peer applications and agents are back-end
servers.</p>

<p>The XML result from a sent request looks like:</p>

<pre>&lt;send count="sent-messages"/></pre>

<p>If there's a response from any agent, the resultset can look like:</p>

<pre>
&lt;send count="sent-messages">
  &lt;agent name="agent1">
    Agent1XML
  &lt;/agent>
  &lt;agent name="agent2">
    Agent2XML
  &lt;/agent>
  ...
&lt;/send>
</pre>

<p>See "<a href="#agents">Agents</a>" for details on connection agents.</p>


<h4><a name="getlist"/>getList()</h4>

<p>To get a list of connected usernames, use the <code>getList()</code>
call. The function takes a comma-separated list of usernames, or use * for all
users. The result is returned in the getListDset dataset like:</p>

<pre>
&lt;list>
  &lt;user name="name1">
  &lt;user name="name2">
  &lt;user name="name3">
  ...
&lt;/list>
</pre>


<h3><a name="events"/>events</h3>

<p>The connection manager and connection datasource can handle these connection
events:</p>

<dl>
  <dt><event>onconnect</event></dt>
  <dd>raised as soon as an established connection is verified.
  </dd>

  <!-- ondata -->
  <dt><event>ondata</event></dt>
  <dd>raised whenever new data arrives for one of the datasource's
  datasets. The root node of the data is returned along with the ondata event
  and looks like:

<pre>
&lt;root dset="dataset">
  arbitraryXML
&lt;/root> </pre>
</dd>

  <!-- onerror -->
  <dt><event>onerror</event></dt>
  <dd>raised if there was a problem establishing the persistent
  connection. An error XML is returned with onerror event and looks like:

  <pre>&lt;error status="code" msg="message"/></pre>
  </dd>


  <!-- ontimeout -->
  <dt><event>ontimeout</event></dt>
  <dd>raised when the client hasn't heard a message or heartbeat
  in the timeout interval. The connection is assumed to be closed if this event
  is raised.
  </dd>

  <!-- ondisconnect -->
  <dt><event>ondisconnect</event></dt>
  <dd>raised right after the persistent connection is
  closed. If the <method>connect</method> method has been called more than once, calling
  <method>disconnect</method> once will not trigger this event until the connection count
  reaches zero.
  </dd>

  <!-- onuserdisconnect -->
  <dt><event>onuserdisconnect</event></dt>
  <dd>raised whenever another client disconnects. The
  connection must have been configured with senduserdisconnect="true".
  </dd>
</dl>

<p>The same events are raised by the connection manager.</p>

<h2><a name="agents"/>Agents</h2>

<p>An agent is a back-end server that pushes and receives client data. LPS
proxies the data between agents and clients. All communication between agent and
LPS is done using HTTP. Only white-listed agent IPs are allowed, which can be
configured using the "connection-agent-ip" option.</p>

<pre>
&lt;option name="connection-agent-ip">
  &lt;allow>
    &lt;pattern>127.0.0.1&lt;/pattern>
  &lt;/allow>
&lt;/option>
</pre>

<p>Agents are associated with an url and one or more connection groups. An agent
can't send or receive data outside of its own group(s). A connection group is a
set of connected applications. Messages sent to a group can be received by
applications and other agents registered to that group. An application with an
unspecified group name has its webapp path as its group. LPS must receive an
agent's url and group with each request for validation.</p>

<p>Agents are configured in the application as child elements of the
connection. For example:</p>

<pre>
&lt;connection group="dashboard">
  &lt;agent url="http://localhost:8080/server-api/History"/>
  &lt;agent url="http://info.com/StockTicker"/>
&lt;/connection>
</pre>

<p>Each declared agent inherits its group from the connection and
requires an url, which serves as the agent's unique identifier and its
location.</p>

<h3><a name="receiving-data"/>Receiving data</h3>

<p>LPS sends data to an agent using the "xml" query parameter. An agent must be
able to accept that parameter and parse its contents. Agents designed only to
push information can choose to ignore this.</p>


<h3><a name="agent-sending-data"/>Sending data</h3>

<p>Agents can use the "agentmessage" LPS request type to send data to clients
and/or other agents. In addition to the validation parameters, "agentmessage"
expects:</p>

<dl>
  <dt><code>to</code></dt>
  <dd>list of names to send data; use * for everyone</dd>
  <dt><code>dset</code></dt>
  <dd>destination dataset; this can be ignored by other
                           agents
  </dd>
  <dt><code>msg</code></dt>
  <dd>arbitrary xml; this parameter is allowed to be
                           empty
  </dd>
  <dt><code>range</code></dt>
  <dd>one of "all", "user", "agent"; if null, default is
                           "all"
  </dd>
</dl>

<p>The query string to LPS should look something like:</p>

<code>
<em>lzt=agentmessage</em>&amp;<em>url</em>=http://info.com/StockTicker&amp;<em>group</em>=business&amp;<em>to</em>=*&amp;<em>dset</em>=portfolio&amp;<em>msg</em>=&lt;url-encoded>&lt;stock-list>
  &lt;stock name="BACL" price="50.0"/>&lt;stock name="BGRT" price="38.0"/>&lt;/stock-list>&lt;/url-encoded>&amp;<em>range</em>=user</code>

<p>The response from LPS will look like:</p>

<pre>
&lt;lps>
  &lt;status>200&lt;/status>
  &lt;message>MESG&lt;/message>
&lt;/lps>
</pre>

<p>where MESG is either "message sent" or "no one specified connected (range:
[all|user|angent])".</p>

<h3><a name="agent-get-list"/>Getting a list of connected users</h3>

<p>The "agentlist" LPS request type sends back a list of connected clients and
expects only the "users" query parameter, which can be a list of names or *. The
query should look something like:</p>

<code>
<em>lzt=agentlist</em>&amp;<em>name</em>=stock&amp;<em>password</em>=secret&amp;<em>group</em>=business&amp;<em>users</em>=*
</code>

<p>The response from LPS will look like:</p>

<pre>
&lt;lps>
  &lt;status>200&lt;/status>
  &lt;message>ok&lt;/message>
  &lt;body>
    &lt;list>
      &lt;user name="name1">
      &lt;user name="name2">
      &lt;user name="name3">
      ...
    &lt;/list>
  &lt;/body>
&lt;/lps>
</pre>


<!--=========================================================================-->
<!-- Authentication                                                          -->
<!--=========================================================================-->
<h2><a name="authentication"/>Authentication</h2>

<p>LPS authenticates all <dfn>server connection requests</dfn> to ensure
that they are not spoofed. Server connection requests are made through
function calls in LzConnection and LzConnectionDatasource. They are
the connect function, the disconnect function, any of the send message
functions, and the get list of connected users function. <fixme>See
"Using connection functions" for more details.</fixme></p>

<p>LPS uses an <dfn>authenticator</dfn> to validate each server connection
request. You can tell LPS what authenticator to use for your connection using
the connection tag's <code>authenticator</code> attribute. Parameters for an
authenticator can be passed through the <code>authparam</code> attribute. The
string has to be in query string format.</p>

<pre>
&lt;connection authenticator="com.mycompany.Security" 
            authparam="usr=myusr&amp;amp;pwd=mypwd"/>
</pre> <!-- plugins -->

<p>Note that &amp;amp; was used to XML escape the ampersand. Be sure to URL
encode values that contain <code>&amp;</code> or <code>=</code> to %26 and %3D,
respectively.</p>

<p>If no authenticator is defined for the connection, LPS uses the
<code><a href="#httpauthentication">HTTPAuthentication</a></code>
authenticator. HTTPAuthentication validates a connection by using an
application's session cookie. It proxies the cookie to a default security server
at <code>http://&lt;lps-host>:&lt;lps-port>/WEBAPP/AuthenticationServlet</code>. You
can specify a different security server by passing an <code>url</code>
parameter:</p>

<pre>
&lt;connection authenticator="org.openlaszlo.auth.HTTPAuthentication"
            authparam="url=http://other.host.com/MySecurityServer"/>
</pre>

<p>If the authentication was successful, the security server should return
HTTPAuthentication a username, which, in turn, is returned to LPS. You can
change the default authenticator with the
<code>connection.default.authenticator</code> LPS property. See the "Deployer's
Guide" for more on how to configure your server and <a
href="#httpauthentication">HTTPAuthentication</a> for what the XML response
format of authentication servers should look like.</p>

<!--=========================================================================-->
<!-- AuthenticationServlet                                                   -->
<!--=========================================================================-->
<h3><a name="authenticationservlet"/>AuthenticationServlet</h3>

<p>The AuthenticationServlet is the default authentication server used by
HTTPAuthentication. You can find the source code for this servlet in
<code>WEB-INF/classes/AuthenticationServlet.java</code>.</p>

<p>AuthenticationServlet provides request types for login (create session),
logout (remove session), and getusername (validate session) as described below
in <a href="#httpauthentication">HTTPAuthentication</a>. During intialization,
AuthenticationServlet reads a list of usernames and passwords from
<code>WEB-INF/lps/config/lzusers.xml</code> to use for login validation. The
format of the file looks like:</p>

<pre>
&lt;users>
  &lt;user name="adam" password="adam"/>
  &lt;user name="bret" password="bret"/>
  ...
&lt;/users>
</pre>


<!--=========================================================================-->
<!-- LPS requests and cookies                                                -->
<!--=========================================================================-->
<!--=========================================================================-->
<!-- Skipping authentication                                                 -->
<!--=========================================================================-->
<h3><a name="skipping-auth"/>Skipping authentication</h3>

<p>You can turn off server authentication by using the anonymous
authenticator.</p>

<pre>
&lt;connection authenticator="anonymous"/>
</pre>

<p>The anonymous authenticator assigns your connection a default username of
<code>user</code>. You can change the default value through the
<code>connection.none-authenticator.username</code> LPS property. Optionally,
you can pass it a <code>usr</code> parameter with the name of your choice. For
example, this sets the connection's username to sam:</p>

<pre>
&lt;connection authenticator="anonymous" authparam="usr=sam"/>
</pre>

<!--=========================================================================-->
<!-- Implementing an authenticator                                           -->
<!--=========================================================================-->
<h3><a name="implementing-an-authenticator"/>Implementing an authenticator</h3>

<p>Connection authenticators are server-side java objects that implement the
<code>org.openlaszlo.servlets.Authentication</code> interface. LPS validates
a request if and only if an authenticator returns a username. Four functions
must be implemented:</p>

<pre>
void <em>init</em>(Properties prop);

String <em>getUsername</em>(HttpServletRequest req, HttpServletResponse res, 
                   HashMap param) 

int <em>login</em>(HttpServletRequest req, HttpServletResponse res,
          HashMap param, StringBuffer xmlResponse)

int <em>logout</em>(HttpServletRequest req, HttpServletResponse res,
           HashMap param, StringBuffer xmlResponse)
</pre>

<p>The <method>init</method> function is called right after an authenticator is
instantiated by LPS. Parameters from the <code>lps.properties</code> file
(located in the <code>WEB-INF/lps/config</code> server directory) are passed
into <method>init</method>.</p>

<p>LPS uses <method>getUsername</method> to authenticate each server connection
request. A value of null is assumed to mean that the request is invalid. Any
other string value, including an empty string, is considered ok.</p>

<p>Both <method>login</method> and <method>logout</method> are used by clients to
session and unsession the application, respectively.</p>


<h4><a name="httpauthentication"/>org.openlaszlo.plugins.HTTPAuthentication</h4>

<p>This class makes HTTP requests to back-end authentication servers to
session/unsession applications and validate connection requests. Required client
cookies are proxied to authentication servers. If set by the authentication
server, response headers are proxied back to the client. HTTPAuthentication
expects the authentication server to handle login, logout, and getusername
request types.</p>

<p>Authentication servers are expected to return an XML response that looks
like:</p>

<pre>
&lt;authentication>
  &lt;response type="<var>login</var>|<var>logout</var>|<var>getusername</var>y">
    &lt;status code="NUMBER" msg="MESSAGE"/>
    [&lt;username>name&lt;/username>]
  &lt;/response>
&lt;/authentication>
</pre>

<p>If a status code doesn't exist or isn't <code>0</code>, the request is assumed
to have failed.</p>

<!--=========================================================================-->
<!-- Login                                                                   -->
<!--=========================================================================-->
<h5><a name="httpauthentication-login"/>Login</h5>

<p>For sessioning, the login query should look like
<code>?rt=login&amp;usr=userame&amp;pwd=secret</code>.</p>

<p>A successful login will look like:</p>

<pre>
&lt;authentication>
   &lt;response type="login">
     &lt;status code="0" msg="ok"/>
     &lt;username>username&lt;/username>
   &lt;/response>
&lt;/authentication>
</pre>

<p>A failed login:</p>

<pre>
&lt;authentication>
  &lt;response type="login">
    &lt;status code="3" msg="invalid"/>
  &lt;/response>
&lt;/authentication>
</pre>

<!--=========================================================================-->
<!-- Logout                                                                  -->
<!--=========================================================================-->
<h5><a name="httpauthentication-logout"/>Logout</h5>

<p>The authentication server must be able to accept the <code>rt=logout</code>
parameter for unsessioning.</p>

<p>A successful logout will look like:</p>

<pre>
&lt;authentication>
  &lt;response type="logout">
    &lt;status code="0" msg="ok"/>
  &lt;/response>
&lt;/authentication>
</pre>

<p>A failed logout:</p>

<pre>
&lt;authentication>
  &lt;response type="logout">
    &lt;status code="4" msg="invalid session"/>
  &lt;/response>
&lt;/authentication>
</pre>

<!--=========================================================================-->
<!-- Getusername                                                             -->
<!--=========================================================================-->
<h5><a name="httpauthentication-getusername">Getusername</a></h5>

<p>For validation, the authentication server must accept the
<code>rt=getusername</code> parameter.</p>

<p>If the client has a valid session, the server should return:</p>
<pre>
&lt;authentication>
  &lt;response type="getusername">
    &lt;status code="0" msg="ok"/>
    &lt;username>username&lt;/username>
  &lt;/response>
&lt;/authentication>
</pre>

<p>If the client has an invalid session, the server should return:</p>
<pre>
 &lt;authentication>
  &lt;response type="getusername">
    &lt;status code="4" msg="invalid session"/>
  &lt;/response>
 &lt;/authentication> 
</pre>

<h4><a name="nullauthentication">org.openlaszlo.servlets.NullAuthentication</a></h4>

<p>Using NullAuthentication is similar to saying:</p>

<pre>&lt;connection authenticator="anonymous"/></pre>

<p>However, NullAuthentication allows you to name your connection:</p>

<pre>
  &lt;connection authenticator="org.openlaszlo.servlets.NullAuthentication"
              authparam="usr=lauren"/>
</pre>

<p>This connection will be named lauren.</p>


<!--=========================================================================-->
<!-- Appendix                                                                -->
<!--=========================================================================-->
<h2><a name="appendix">Appendix</a></h2>

<h3><a name="glossary">Glossary</a></h3>

<p><b>agent</b>: a back-end server that pushes data to clients and/or other agents,
and vice-versa.</p>

<p><b>application</b>: an LZX program.</p>

<p><b>authenticator</b>: the server-side java object that authenticates server
connection requests.</p>

<p><b>connection</b>: (see persistent connection)</p>

<p><b>connection datasource</b>: See LzConnectionDatasource in the LZX
Reference.</p>

<p><b>connection manager</b>: a handler that multiplexes all incoming connection
data through a connection datasource into a dataset. See LzConnection in the LZX
Reference.</p>

<p><b>connection session id</b>: the unique identifier of a persistent
connection.</p>

<p><b>server connection requests</b>: LzConnection and LzConnectionDatasource
function calls that make requests to LPS. They are <method>connect</method>,
<method>disconnect</method>, <method>sendMessage</method>, <method>sendXML</method>,
<method>sendUserXML</method>, and <method>sendAgentXML</method>.</p>

<p><b>group</b>: a set of applications that can push messages to each other.</p>

<p><b>heartbeat</b>: a server to client ping to verify that a connection is
still alive.</p>

<p><b>persistent connection</b>: a one-way pipeline from server to client that
allows an application to receive asynchronous data.</p>

<p><b>session id</b>: (see connection session id)</p>

<p><b>username</b>: a connection name for other applications to target. This
value may not be unique among different connections.</p>

<h3><a name="demos">Demo applications</a></h3>
<ul>
<li>Chat (demos/chat/chat.lzx)</li>
<li>Dashboard (demos/dashboard/dashboard.lzx)</li>
</ul>

</body>
</html>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2001-2004 Laszlo Systems, Inc.  All Rights Reserved.              *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
